﻿using System;
using System.IO;
using System.Net;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;
using System.Net.Sockets;
using System.Collections.Generic;

namespace PlanningGIS.Util.Net
{
    /// <summary>
    /// ftp服务。
    /// FTP的传输类型分为ASCII码方式和二进制方式两种，
    /// 对.txt、.htm等文件应采用ASCII码方式传输，对.exe或图片、视频、音频等文件应采用二进制方式传输。
    /// 在默认情况下，FTP为ASCII码传输方式。
    /// </summary>
    [Obsolete("已废弃，请使用FTPRequest")]
    public class FTPService
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        public FTPService()
        {
            this.Server = "127.0.0.1";
            this.Timeout = 100;
            this.Port = 21;
            Pause = false;
            timer = new System.Timers.Timer(1000);
            timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
            timer.Start();
        }

        
        /// <summary>
        /// 
        /// </summary>
        private System.Timers.Timer timer = null;
        /// <summary>
        /// 缓冲大小
        /// </summary>
        private static int BUFFER_SIZE = 512;
        
        /// <summary>
        /// 字符编码
        /// </summary>
        private static Encoding ASCII = Encoding.ASCII;
        
        /// <summary>
        /// 执行的消息
        /// </summary>
        private string message = null;
        
        /// <summary>
        /// 返回的结果消息
        /// </summary>
        private string result = null;
        
        /// <summary>
        /// 执行的byte数
        /// </summary>
        private int bytes = 0;
        
        /// <summary>
        /// 返回的结果代码
        /// </summary>
        private int resultCode = 0;
        
        /// <summary>
        /// 是否已登录
        /// </summary>
        private bool loggedin = false;        
        
        /// <summary>
        /// 缓冲区字节数
        /// </summary>
        private Byte[] buffer = new Byte[BUFFER_SIZE];
        
        /// <summary>
        /// 客户端Socket
        /// </summary>
        private Socket clientSocket = null;
        
        /// <summary>
        /// 获取或设置服务器端口号，默认端口 21
        /// </summary>
        public int Port { get; set; }
        
        /// <summary>
        /// 获取或设置超时时间
        /// </summary>
        public int Timeout { get; set; }
        
        /// <summary>
        /// 获取或设置服务器IP地址
        /// </summary>
        public string Server { get; set; }
        
        /// <summary>
        /// 获取或设置服务器路径
        /// </summary>
        public string RemotePath { get; set; }
        
        /// <summary>
        /// 获取或设置ftp用户
        /// </summary>
        public string Username { get; set; }
        
        /// <summary>
        /// 获取或设置ftp密码
        /// </summary>
        public string Password { get; set; }

        /// <summary>
        /// 操作是否暂停
        /// </summary>
        public bool Pause { get; set; }
        
        /// <summary>
        /// 传输类型
        /// </summary>
        private bool binMode = false;
        
        /// <summary>
        /// 是否为二进制模式，若为true，则使用binary，否则使用Ascii。
        /// </summary>
        public bool BinaryMode
        {
            get { return this.binMode; }
            set
            {
                if (this.binMode == value) return;
                if (value)
                    sendCommand("TYPE I");  //binary 
                else
                    sendCommand("TYPE A");  //ascii 
                if (this.resultCode != 200) 
                    throw new Exception(result.Substring(4));
            }
        }

        /// <summary>
        /// 获取当前操作执行的结果
        /// </summary>
        public dynamic Result { get; private set; }

        /// <summary>
        /// 登录到服务器
        /// </summary>
        /// <returns>登录是否成功</returns>
        public bool Login()
        {
            if (this.loggedin) this.Close();
            try
            {
                this.clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                this.clientSocket.Connect(IPAddress.Parse(this.Server), this.Port);
            }
            catch (Exception ex)
            {
                if (this.clientSocket != null && this.clientSocket.Connected) 
                    this.clientSocket.Close();
                this.Result = "连接服务器" + this.Server + "失败：" + ex.Message;
                return false;
            }
            this.readResponse();
            if (this.resultCode != 220)
            {
                this.Close();
                this.Result = string.IsNullOrWhiteSpace(this.result) ? this.resultCode.ToString() : this.result.Substring(4);
                return false;
            }
            this.sendCommand("USER " + Username);
            if (!(this.resultCode == 331 || this.resultCode == 230))
            {
                this.cleanup();
                this.Result = this.result.Substring(4);
                return false;
            }
            if (this.resultCode != 230)
            {
                this.sendCommand("PASS " + Password);
                if (!(this.resultCode == 230 || this.resultCode == 202))
                {
                    this.cleanup();
                    this.Result = this.result.Substring(4);
                    return false;
                }
            }
            this.loggedin = true;
            this.ChangeDir(this.RemotePath);
            return true;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        private bool Connect()
        {
            try
            {
                this.clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                this.clientSocket.Connect(IPAddress.Parse(this.Server), this.Port);
                return true;
            }
            catch (Exception ex)
            {
                if (this.clientSocket != null && this.clientSocket.Connected)
                    this.clientSocket.Close();
                this.Result = "连接服务器" + this.Server + "失败：" + ex.Message;
                return false;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            if (!this.loggedin) return;
            if (this.clientSocket == null || !this.clientSocket.Connected)
            {
                Close();
            }
        }

        /// <summary>
        /// 关闭FTP连接
        /// </summary>
        public void Close()
        {
            try
            {
                if (this.clientSocket != null)
                {
                    this.sendCommand("QUIT");
                }
                this.cleanup();
            }
            catch
            {
                loggedin = false;
            }
        }

        /// <summary>
        /// 设置当前传输的模式
        /// </summary>
        /// <param name="filename"></param>
        private void SetModeType(string filename)
        {
            filename = filename.ToLower().Trim();
            //if (filename.EndsWith(".txt") || filename.EndsWith(".htm"))
            //    this.BinaryMode = false;
            //else
            //    this.BinaryMode = true;
            this.BinaryMode = true;
        }

        /// <summary>
        /// 获取当前目录下的所有文件列表
        /// </summary>
        /// <returns></returns>
        public string[] GetFileList()
        {
            return this.GetFileList("*.*");
        }

        /// <summary>
        /// 获取文件或目录列表
        /// </summary>
        /// <param name="mask">查找条件，如*.*</param>
        /// <returns></returns>
        public string[] GetFileList(string mask)
        {
            this.Result = "";
            if (!this.loggedin) this.Login();
            if (!this.loggedin)
            {
                this.Result = "FTP连接失败";
                return null;
            }
            Socket cSocket = CreateDataSocket();
            if (cSocket == null)
            {
                this.Result = "创建连接失败";
                return null;
            }
            this.BinaryMode = false;
            this.sendCommand("NLST " + mask);
            if (!(this.resultCode == 150 || this.resultCode == 125))
            {
                return null;
            }
            this.message = "";
            DateTime timeout = DateTime.Now.AddSeconds(this.Timeout);
            while (timeout > DateTime.Now)
            {
                int bytes = cSocket.Receive(buffer, buffer.Length, 0);
                this.message += ASCII.GetString(buffer, 0, bytes);
                if (bytes < this.buffer.Length) break;
            }
            cSocket.Close();
            message = message.Replace("\r", "").Trim();
            if (message.EndsWith("\n")) message = message.Substring(0, message.Length - 2);
            string[] msg = this.message.Split('\n');
            if (string.IsNullOrEmpty(message) || string.IsNullOrWhiteSpace(message))
                msg = new string[] { };
            if (this.message.IndexOf("No such file or directory") != -1)
                msg = new string[] { };
            this.readResponse();
            if (this.resultCode != 226)
                msg = new string[] { };
            return msg;
        }

        /// <summary>
        /// 获取指定目录中的文件或目录列表
        /// </summary>
        /// <param name="dir">要查找的目录</param>
        /// <param name="mask">查找条件，默认为"*.*"</param>
        /// <returns></returns>
        public string[] GetFileList(string dir, string mask)
        {
            if (string.IsNullOrEmpty(mask) || string.IsNullOrWhiteSpace(mask)) mask = "*.*";
            if (!string.IsNullOrEmpty(dir) && !string.IsNullOrWhiteSpace(dir))
            {
                string[] dirs = dir.Replace("/", @"\").Split('\\');
                if (dirs.Length > 1) this.ChangeDir("\\");   //返回根目录
                for (int i = 0; i < dirs.Length; i++)
                {
                    string dname = dirs[i];
                    if (string.IsNullOrEmpty(dname) || string.IsNullOrWhiteSpace(dname)) continue;
                    if (ExistDir(dname))
                        this.ChangeDir(dname);
                    else   //目录不存在
                    {
                        this.Result = "目录【" + dname + "】不存在";
                        this.ChangeDir("\\"); //返回根目录
                        return null;
                    }
                }
            }
            string[] files = GetFileList(mask);
            this.ChangeDir("\\"); //返回根目录
            return files;
        }

        /// <summary>
        /// 查找指定条件的文件是否存在
        /// </summary>
        /// <param name="mask">查找条件，默认为"*.*"</param>
        /// <returns></returns>
        public bool ExistsFile(string mask)
        {
            string[] files = GetFileList(mask);
            if (files == null || files.Length == 0) return false;
            return true;
        }

        /// <summary>
        /// 查找指定目录下满足条件的文件是否存在
        /// </summary>
        /// <param name="dir">要查找的目录</param>
        /// <param name="mask">查找条件，默认为"*.*"</param>
        /// <returns></returns>
        public bool ExistFile(string dir, string mask)
        {
            string[] files = GetFileList(dir, mask);
            if (files == null || files.Length == 0) return false;
            return true;
        }

        /// <summary>
        /// 获取文件的大小
        /// </summary>
        /// <param name="fileName">文件名称</param>
        /// <returns></returns>
        public long GetFileSize(string fileName)
        {
            if (!this.loggedin) this.Login();
            this.sendCommand("SIZE " + fileName);
            long size = 0;
            if (this.resultCode == 213)
                size = long.Parse(this.result.Substring(4));
            else
            {
                size = 0;
                this.Result = this.result.Substring(4);
            }
            return size;
        }

        /// <summary>
        /// 以同名下载当前目录下的指定的文件。本地的目录必需存在
        /// </summary>
        /// <param name="remFileName">要下载的文件</param>
        /// <returns></returns>
        public bool Download(string remFileName)
        {
            return this.Download(remFileName, "", false);
        }

        /// <summary>
        /// 以同名下载当前目录下的指定的文件。本地的目录必需存在
        /// </summary>
        /// <param name="remFileName">要下载的文件</param>
        /// <param name="resume">是否使用断点下载,为true时表示支持断点续传,可中途暂停</param>
        /// <returns></returns>
        public bool Download(string remFileName, bool resume)
        {
            return this.Download(remFileName, "", resume);
        }

        /// <summary>
        /// 下载文件，并保存为指定的名称。本地的目录必需存在
        /// </summary>
        /// <param name="remFileName">要下载的文件</param>
        /// <param name="locFileName">要保存的名称</param>
        /// <returns></returns>
        public bool Download(string remFileName, string locFileName)
        {
            return this.Download(remFileName, locFileName, false);
        }

        /// <summary>
        /// 下载文件，并保存为指定的名称。本地的目录必需存在
        /// </summary>
        /// <param name="remFileName">要下载的文件</param>
        /// <param name="locFileName">要保存的名称</param>
        /// <param name="resume">是否使用断点下载,为true时表示支持断点续传,可中途暂停</param>
        /// <returns></returns>
        public bool Download(string remFileName, string locFileName, bool resume)
        {
            if (string.IsNullOrEmpty(remFileName) || string.IsNullOrWhiteSpace(remFileName)) return false;
            this.Pause = false;
            if (!this.loggedin) this.Login();
            string[] dirs = remFileName.Replace("/", @"\").Split('\\');
            if (dirs.Length > 1) this.ChangeDir("\\");   //返回根目录
            string fi = dirs[dirs.Length - 1];
            for (int i = 0; i < dirs.Length-1; i++)
            {
                string dname = dirs[i];
                if (string.IsNullOrEmpty(dname) || string.IsNullOrWhiteSpace(dname)) continue;
                if (ExistDir(dname))
                    this.ChangeDir(dname);
                else
                {
                    this.Result = "目录【" + dname + "】不存在";
                    return false;
                }
            }
            //this.BinaryMode = true;
            SetModeType(remFileName);
            if (string.IsNullOrEmpty(locFileName) || string.IsNullOrWhiteSpace(locFileName)) locFileName = fi;
            FileStream output = null;
            if (!File.Exists(locFileName))
                output = File.Create(locFileName);
            else
                output = new FileStream(locFileName, FileMode.Open);
            Socket cSocket = CreateDataSocket();
            long offset = 0;
            if (resume)
            {
                offset = output.Length;
                if (offset > 0)
                {
                    this.sendCommand("REST " + offset);
                    if (this.resultCode != 350)
                    {
                        offset = 0;
                    }
                    else
                    {
                        output.Seek(offset, SeekOrigin.Begin);
                    }
                }
            }
            this.sendCommand("RETR " + fi);
            if (this.resultCode != 150 && this.resultCode != 125)
            {
                this.ChangeDir("\\"); //返回根目录
                this.Result = this.result.Substring(4);
                return false;
            }
            DateTime timeout = DateTime.Now.AddSeconds(this.Timeout);
            while (timeout > DateTime.Now)
            {
                if (this.Pause) break;
                this.bytes = cSocket.Receive(buffer, buffer.Length, 0);
                output.Write(this.buffer, 0, this.bytes);
                if (this.bytes <= 0)
                {
                    break;
                }
            }
            output.Close();
            if (cSocket.Connected) cSocket.Close();
            this.readResponse();
            if (this.resultCode != 226 && this.resultCode != 250)
            {
                this.ChangeDir("\\"); //返回根目录
                this.Result = this.result.Substring(4);
                return false;
            }
            this.ChangeDir("\\");   //返回根目录
            return true;
        }

        /// <summary>
        /// 上传文件
        /// </summary>
        /// <param name="fileName">要上传的文件的全路径</param>
        /// <returns></returns>
        public bool Upload(string fileName)
        {
            return this.Upload(fileName, fileName, false);
        }

        /// <summary>
        /// 上传文件
        /// </summary>
        /// <param name="fileName">要上传的文件的全路径</param>
        /// <param name="resume">是否使用断点下载,为true时表示支持断点续传,可中途暂停</param>
        /// <returns></returns>
        public bool Upload(string fileName, bool resume)
        {
            return this.Upload(fileName, fileName, resume);
        }

        /// <summary>
        /// 上传文件
        /// </summary>
        /// <param name="fileName">要上传的文件的全路径</param>
        /// <param name="toName">要上传到的相对文件路径</param>
        /// <param name="resume">是否使用断点下载,为true时表示支持断点续传,可中途暂停</param>
        /// <returns></returns>
        public bool Upload(string fileName, string toName, bool resume)
        {
            if (!this.loggedin) this.Login();
            if (!this.loggedin)
            {
                this.Result = "FTP连接失败" + this.result;
                return false;
            }
            string[] dirs = toName.Replace("/", @"\").Split('\\');
            if (dirs.Length > 1)
            {
                for (int i = 0; i < dirs.Length - 1; i++)
                {
                    string dname = dirs[i];
                    if (string.IsNullOrEmpty(dname) || string.IsNullOrWhiteSpace(dname)) continue;
                    if (ExistDir(dname))
                        this.ChangeDir(dname);
                    else
                    {
                        if (this.MakeDir(dname)) this.ChangeDir(dname);
                        else return false;
                    }
                }
                toName = dirs[dirs.Length - 1];
            }
            SetModeType(fileName);
            Socket cSocket = null;
            long offset = 0;
            if (resume)
            {
                try
                {
                    this.BinaryMode = true;
                    offset = GetFileSize(toName);
                }
                catch
                {
                    offset = 0;
                }
            }
            FileStream input = new FileStream(fileName, FileMode.Open);
            if (resume && input.Length < offset)
            {
                offset = 0;
            }
            else if (resume && input.Length == offset) 
            {
                input.Close();
                this.ChangeDir("\\"); //返回根目录
                return true;
            }
            cSocket = this.CreateDataSocket();
            if (offset > 0)
            {
                this.sendCommand("REST " + offset);
                if (this.resultCode != 350)
                {
                    offset = 0;
                }
            }
            this.sendCommand("STOR " + toName);
            if (this.resultCode != 125 && this.resultCode != 150) throw new Exception(result.Substring(4));
            if (offset != 0)
            {
                input.Seek(offset, SeekOrigin.Begin);
            }
            while ((bytes = input.Read(buffer, 0, buffer.Length)) > 0)
            {
                cSocket.Send(buffer, bytes, 0);
            }
            input.Close();
            if (cSocket.Connected)
            {
                cSocket.Close();
            }
            this.readResponse();
            if (this.resultCode != 226 && this.resultCode != 250)
            {
                this.ChangeDir("\\");
                this.Result = this.result.Substring(4);
                return false;
            }
            this.ChangeDir("\\"); //返回根目录
            return true;
        }

        /// <summary>
        /// 上传文件夹及其文件
        /// </summary>
        /// <param name="path">要上传的文件夹</param>
        /// <param name="recurse">是否递归子目录</param>
        /// <returns></returns>
        public bool UploadDirectory(string path, bool recurse)
        {
            return this.UploadDirectory(path, recurse, "*.*");
        }

        /// <summary>
        /// 上传文件夹及其文件[未完成]
        /// </summary>
        /// <param name="path">要上传的文件夹</param>
        /// <param name="recurse">是否递归子目录</param>
        /// <param name="mask">只上传指定格式的文件，所有文件为： '*.*'</param>
        /// <returns></returns>
        public bool UploadDirectory(string path, bool recurse, string mask)
        {
            string[] dirs = path.Replace("/", @"\").Split('\\');
            string rootDir = dirs[dirs.Length - 1];
            string[] fs = this.GetFileList(rootDir);
            if (fs == null || fs.Length < 1) this.MakeDir(rootDir);
            bool isfalse = false;
            this.ChangeDir(rootDir);
            foreach (string file in Directory.GetFiles(path, mask))
            {
                isfalse = this.Upload(file, true);

            }
            if (recurse)
            {
                foreach (string directory in Directory.GetDirectories(path))
                {
                    this.UploadDirectory(directory, recurse, mask);
                }
            }
            this.ChangeDir("..");  //返回至上一级目录
            return true;
        }

        /// <summary>
        /// 删除Ftp服务器中的文件
        /// </summary>
        /// <param name="fileName">要删除的文件名称</param>
        /// <returns></returns>
        public bool DeleteFile(string fileName)
        {
            if (!this.loggedin) this.Login();
            this.sendCommand("DELE " + fileName);
            if (this.resultCode != 250)
            {
                this.Result = this.result.Substring(4);
                return false;
            }
            return true;
        }

        /// <summary>
        /// 删除指定目录下的文件
        /// </summary>
        /// <param name="dir"></param>
        /// <param name="filename"></param>
        /// <returns></returns>
        public bool DeleteFile(string dir, string filename)
        {
            if (!string.IsNullOrEmpty(dir) && !string.IsNullOrWhiteSpace(dir))
            {
                string[] dirs = dir.Replace("/", @"\").Split('\\');
                if (dirs.Length > 1) this.ChangeDir("\\");   //返回根目录
                for (int i = 0; i < dirs.Length; i++)
                {
                    string dname = dirs[i];
                    if (string.IsNullOrEmpty(dname) || string.IsNullOrWhiteSpace(dname)) continue;
                    if (ExistDir(dname))
                        this.ChangeDir(dname);
                    else   //目录不存在
                    {
                        this.Result = "目录【" + dname + "】不存在";
                        this.ChangeDir("\\"); //返回根目录
                        return true;
                    }
                }
            }
            bool issuc = DeleteFile(filename);
            this.ChangeDir("\\"); //返回根目录
            return issuc;
        }

        /// <summary>
        /// 修改Ftp服务器中文件的名称
        /// </summary>
        /// <param name="oldFileName">之前的名称</param>
        /// <param name="newFileName">修改后的名称</param>
        /// <param name="overwrite">若文件已存在是否重写</param>
        /// <returns></returns>
        public bool RenameFile(string oldFileName, string newFileName, bool overwrite)
        {
            if (!this.loggedin) this.Login();
            this.sendCommand("RNFR " + oldFileName);
            if (this.resultCode != 350)
            {
                this.Result = this.result.Substring(4);
                return false;
            }
            string[] fs = this.GetFileList(newFileName);
            if (!overwrite && (fs == null || fs.Length > 0))
            {
                this.Result = "已经存在该名称，不能重命名";
                return false;
            }
            this.sendCommand("RNTO " + newFileName);
            if (this.resultCode != 250)
            {
                this.Result = this.result.Substring(4);
                return false;
            }
            return true;
        }

        /// <summary>
        /// 查找当前目录下是否存在指定的目录
        /// </summary>
        /// <param name="dirname">目录名称</param>
        /// <returns></returns>
        private bool ExistDir(string dirname)
        {
            string[] files = GetFileList(dirname);
            if (files == null || files.Length == 0) return false;
            return true;
        }
        
        /// <summary>
        /// 在Ftp服务器中创建目录
        /// </summary>
        /// <param name="dirName">目录名称</param>
        /// <returns></returns>
        public bool MakeDir(string dirName)
        {
            if (!this.loggedin) this.Login();
            this.sendCommand("MKD " + dirName);
            if (this.resultCode != 250 && this.resultCode != 257)
            {
                this.Result = "目录【" + dirName + "】创建失败，请检查用户是否有操作权限！" + this.result.Substring(4);
                return false;
            }
            return true;
        }

        /// <summary>
        /// 删除Ftp服务器中的目录
        /// </summary>
        /// <param name="dirName">目录名称</param>
        /// <returns></returns>
        public bool RemoveDir(string dirName)
        {
            if (!this.loggedin) this.Login();
            this.sendCommand("RMD " + dirName);
            if (this.resultCode != 250)
            {
                this.Result = this.result.Substring(4);
                return false;
            }
            return true;
        }

        /// <summary>
        /// 改变Ftp服务器中当前的工作目录
        /// </summary>
        /// <param name="dirName">目录名称</param>
        /// <returns></returns>
        public bool ChangeDir(string dirName)
        {
            if (dirName == null || dirName.Equals(".") || dirName.Length == 0)
            {
                return true;
            }
            if (!this.loggedin) this.Login();
            this.sendCommand("CWD " + dirName);
            if (this.resultCode != 250)
            {
                this.Result = this.result.Substring(4);
                return false;
            }
            this.sendCommand("PWD");
            if (this.resultCode != 257)
            {
                this.Result = this.result.Substring(4);
                return false;
            }
            this.RemotePath = this.message.Split('"')[1];
            return true;
        }

        /// <summary>
        /// 发送Ftp命令
        /// </summary>
        /// <param name="command"></param>
        private void sendCommand(string command)
        {
            Byte[] cmdBytes = Encoding.Default.GetBytes((command + "\r\n").ToCharArray());
            clientSocket.Send(cmdBytes, cmdBytes.Length, 0);
            this.readResponse();
        }

        /// <summary>
        /// 读取数据流
        /// </summary>
        private void readResponse()
        {
            this.message = "";
            this.result = this.readLine();
            if (this.result.Length > 3)
                this.resultCode = int.Parse(this.result.Substring(0, 3));
            else
                this.result = "";
        }

        /// <summary>
        /// 读取数据流的行数据
        /// </summary>
        /// <returns></returns>
        private string readLine()
        {
            while (true)
            {
                this.bytes = clientSocket.Receive(this.buffer, this.buffer.Length, 0);
                this.message += ASCII.GetString(this.buffer, 0, this.bytes);
                if (this.bytes < this.buffer.Length)
                {
                    break;
                }
            }
            string[] msg = this.message.Split('\n');
            if (this.message.Length > 2)
                this.message = msg[msg.Length - 2];
            else
                this.message = msg[0];
            if (this.message.Length > 4 && !this.message.Substring(3, 1).Equals(" ")) return this.readLine();            
            return message;
        }
        
        /// <summary>
        /// 在文件传送时创建一个Socket连接
        /// </summary>
        /// <returns>Connected socket</returns>
        private Socket CreateDataSocket()
        {
            this.sendCommand("PASV");
            if (this.resultCode != 227)
            {
                this.Result = this.result.Substring(4);
                return null;
            }
            int index1 = this.result.IndexOf('(');
            int index2 = this.result.IndexOf(')');
            string ipData = this.result.Substring(index1 + 1, index2 - index1 - 1);
            int[] parts = new int[6];
            int len = ipData.Length;
            int partCount = 0;
            string buf = "";
            for (int i = 0; i < len && partCount <= 6; i++)
            {
                char ch = char.Parse(ipData.Substring(i, 1));
                if (char.IsDigit(ch))
                    buf += ch;
                else if (ch != ',')
                {
                    this.Result = "命令【PASV】无效: " + result;
                    return null;
                }
                if (ch == ',' || i + 1 == len)
                {
                    try
                    {
                        parts[partCount++] = int.Parse(buf);
                        buf = "";
                    }
                    catch (Exception ex)
                    {
                        this.Result = "不支持命令【PASV】: " + result + "。" + ex.Message;
                        return null;
                    }
                }
            }
            string ipAddress = parts[0] + "." + parts[1] + "." + parts[2] + "." + parts[3];
            int port = (parts[4] << 8) + parts[5];
            Socket socket = null;
            try
            {
                socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                socket.Connect(IPAddress.Parse(ipAddress), port);
            }
            catch (Exception ex)
            {
                if (socket != null && socket.Connected) socket.Close();
                this.Result = "无法连接到远程服务器: "  + ex.Message;
                return null;
            }
            return socket;
        }

        /// <summary>
        /// 释放所有的连接
        /// </summary>
        private void cleanup()
        {
            if (this.clientSocket != null)
            {
                this.clientSocket.Close();
                this.clientSocket = null;
            }
            this.loggedin = false;
        }

        /// <summary>
        /// 析构函数，释放资源
        /// </summary>
        ~FTPService()
        {
            //this.cleanup();
            timer.Stop();
            Close();
            
        }

        #region 异步操作方法
        /// <summary>
        /// 登录回调委托
        /// </summary>
        /// <returns>登录是否成功</returns>
        private delegate bool LoginCallback();
        /// <summary>
        /// 开始异步登录
        /// </summary>
        /// <param name="callback">回调事件</param>
        /// <returns></returns>
        public System.IAsyncResult BeginLogin(System.AsyncCallback callback)
        {
            LoginCallback ftpCallback = new LoginCallback(this.Login);
            return ftpCallback.BeginInvoke(callback, null);
        }
        /// <summary>
        /// 关闭回调委托
        /// </summary>
        private delegate void CloseCallback();
        /// <summary>
        /// 开始异步关闭
        /// </summary>
        /// <param name="callback">回调事件</param>
        /// <returns></returns>
        public System.IAsyncResult BeginClose(System.AsyncCallback callback)
        {
            CloseCallback ftpCallback = new CloseCallback(this.Close);
            return ftpCallback.BeginInvoke(callback, null);
        }
        /// <summary>
        /// 获取文件或目录回调委托
        /// </summary>
        /// <returns></returns>
        private delegate String[] GetFileListCallback();
        /// <summary>
        /// 开始异步获取文件列表
        /// </summary>
        /// <param name="callback">回调事件</param>
        /// <returns></returns>
        public System.IAsyncResult BeginGetFileList(System.AsyncCallback callback)
        {
            GetFileListCallback ftpCallback = new GetFileListCallback(this.GetFileList);
            return ftpCallback.BeginInvoke(callback, null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="mask"></param>
        /// <returns></returns>
        private delegate String[] GetFileListMaskCallback(String mask);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="mask"></param>
        /// <param name="callback">回调事件</param>
        /// <returns></returns>
        public System.IAsyncResult BeginGetFileList(String mask, System.AsyncCallback callback)
        {
            GetFileListMaskCallback ftpCallback = new GetFileListMaskCallback(this.GetFileList);
            return ftpCallback.BeginInvoke(mask, callback, null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        private delegate Int64 GetFileSizeCallback(String fileName);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="callback">回调事件</param>
        /// <returns></returns>
        public System.IAsyncResult BeginGetFileSize(String fileName, System.AsyncCallback callback)
        {
            GetFileSizeCallback ftpCallback = new GetFileSizeCallback(this.GetFileSize);
            return ftpCallback.BeginInvoke(fileName, callback, null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="remFileName"></param>
        private delegate bool DownloadCallback(String remFileName);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="remFileName"></param>
        /// <param name="callback"></param>
        /// <returns></returns>
        public System.IAsyncResult BeginDownload(String remFileName, System.AsyncCallback callback)
        {
            DownloadCallback ftpCallback = new DownloadCallback(this.Download);
            return ftpCallback.BeginInvoke(remFileName, callback, null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="remFileName"></param>
        /// <param name="resume"></param>
        private delegate bool DownloadFileNameResumeCallback(String remFileName, Boolean resume);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="remFileName"></param>
        /// <param name="resume"></param>
        /// <param name="callback"></param>
        /// <returns></returns>
        public System.IAsyncResult BeginDownload(String remFileName, Boolean resume, System.AsyncCallback callback)
        {
            DownloadFileNameResumeCallback ftpCallback = new DownloadFileNameResumeCallback(this.Download);
            return ftpCallback.BeginInvoke(remFileName, resume, callback, null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="remFileName"></param>
        /// <param name="locFileName"></param>
        private delegate bool DownloadFileNameFileNameCallback(String remFileName, String locFileName);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="remFileName"></param>
        /// <param name="locFileName"></param>
        /// <param name="callback"></param>
        /// <returns></returns>
        public System.IAsyncResult BeginDownload(String remFileName, String locFileName, System.AsyncCallback callback)
        {
            DownloadFileNameFileNameCallback ftpCallback = new DownloadFileNameFileNameCallback(this.Download);
            return ftpCallback.BeginInvoke(remFileName, locFileName, callback, null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="remFileName"></param>
        /// <param name="locFileName"></param>
        /// <param name="resume"></param>
        private delegate bool DownloadFileNameFileNameResumeCallback(String remFileName, String locFileName, Boolean resume);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="remFileName"></param>
        /// <param name="locFileName"></param>
        /// <param name="resume"></param>
        /// <param name="callback"></param>
        /// <returns></returns>
        public System.IAsyncResult BeginDownload(String remFileName, String locFileName, Boolean resume, System.AsyncCallback callback)
        {
            DownloadFileNameFileNameResumeCallback ftpCallback = new DownloadFileNameFileNameResumeCallback(this.Download);
            return ftpCallback.BeginInvoke(remFileName, locFileName, resume, callback, null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="fileName"></param>
        private delegate bool UploadCallback(String fileName);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="callback"></param>
        /// <returns></returns>
        public System.IAsyncResult BeginUpload(String fileName, System.AsyncCallback callback)
        {
            UploadCallback ftpCallback = new UploadCallback(this.Upload);
            return ftpCallback.BeginInvoke(fileName, callback, null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="resume"></param>
        private delegate bool UploadFileNameResumeCallback(String fileName, Boolean resume);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="resume"></param>
        /// <param name="callback"></param>
        /// <returns></returns>
        public System.IAsyncResult BeginUpload(String fileName, Boolean resume, System.AsyncCallback callback)
        {
            UploadFileNameResumeCallback ftpCallback = new UploadFileNameResumeCallback(this.Upload);
            return ftpCallback.BeginInvoke(fileName, resume, callback, null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="path"></param>
        /// <param name="recurse"></param>
        private delegate bool UploadDirectoryCallback(String path, Boolean recurse);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="path"></param>
        /// <param name="recurse"></param>
        /// <param name="callback"></param>
        /// <returns></returns>
        public System.IAsyncResult BeginUploadDirectory(String path, Boolean recurse, System.AsyncCallback callback)
        {
            UploadDirectoryCallback ftpCallback = new UploadDirectoryCallback(this.UploadDirectory);
            return ftpCallback.BeginInvoke(path, recurse, callback, null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="path"></param>
        /// <param name="recurse"></param>
        /// <param name="mask"></param>
        private delegate bool UploadDirectoryPathRecurseMaskCallback(String path, Boolean recurse, String mask);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="path"></param>
        /// <param name="recurse"></param>
        /// <param name="mask"></param>
        /// <param name="callback"></param>
        /// <returns></returns>
        public System.IAsyncResult BeginUploadDirectory(String path, Boolean recurse, String mask, System.AsyncCallback callback)
        {
            UploadDirectoryPathRecurseMaskCallback ftpCallback = new UploadDirectoryPathRecurseMaskCallback(this.UploadDirectory);
            return ftpCallback.BeginInvoke(path, recurse, mask, callback, null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="fileName"></param>
        private delegate bool DeleteFileCallback(String fileName);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="callback"></param>
        /// <returns></returns>
        public System.IAsyncResult BeginDeleteFile(String fileName, System.AsyncCallback callback)
        {
            DeleteFileCallback ftpCallback = new DeleteFileCallback(this.DeleteFile);
            return ftpCallback.BeginInvoke(fileName, callback, null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="oldFileName"></param>
        /// <param name="newFileName"></param>
        /// <param name="overwrite"></param>
        private delegate bool RenameFileCallback(String oldFileName, String newFileName, Boolean overwrite);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="oldFileName"></param>
        /// <param name="newFileName"></param>
        /// <param name="overwrite"></param>
        /// <param name="callback"></param>
        /// <returns></returns>
        public System.IAsyncResult BeginRenameFile(String oldFileName, String newFileName, Boolean overwrite, System.AsyncCallback callback)
        {
            RenameFileCallback ftpCallback = new RenameFileCallback(this.RenameFile);
            return ftpCallback.BeginInvoke(oldFileName, newFileName, overwrite, callback, null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="dirName"></param>
        private delegate bool MakeDirCallback(String dirName);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="dirName"></param>
        /// <param name="callback"></param>
        /// <returns></returns>
        public System.IAsyncResult BeginMakeDir(String dirName, System.AsyncCallback callback)
        {
            MakeDirCallback ftpCallback = new MakeDirCallback(this.MakeDir);
            return ftpCallback.BeginInvoke(dirName, callback, null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="dirName"></param>
        private delegate bool RemoveDirCallback(String dirName);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="dirName"></param>
        /// <param name="callback"></param>
        /// <returns></returns>
        public System.IAsyncResult BeginRemoveDir(String dirName, System.AsyncCallback callback)
        {
            RemoveDirCallback ftpCallback = new RemoveDirCallback(this.RemoveDir);
            return ftpCallback.BeginInvoke(dirName, callback, null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="dirName"></param>
        private delegate bool ChangeDirCallback(String dirName);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="dirName"></param>
        /// <param name="callback"></param>
        /// <returns></returns>
        public System.IAsyncResult BeginChangeDir(String dirName, System.AsyncCallback callback)
        {
            ChangeDirCallback ftpCallback = new ChangeDirCallback(this.ChangeDir);
            return ftpCallback.BeginInvoke(dirName, callback, null);
        }

        #endregion
    }
}
